//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>
#include <drvpub.h>
#include <define.h>
#include "sercommdev.h"
#include <serialio.h>


#define xs_setgpio_AFR          Gpio_SetAFR
#define xs_setgpio_dir          Gpio_SetDir
#define xs_setgpio_outlow       Gpio_SetOutLow
#define xs_setgpio_outhigh      Gpio_SetOutHigh
#define xs_getgpio_inLEV        xs_getgpio_inLEV

#define GPIO_PIN_IN	0
#define GPIO_PIN_OUT	1

#define GPIO_LOW	0
#define GPIO_HIGH	1

#define GPIO_AS_GPIO	0
#define GPIO_AS_AF1	1
#define GPIO_AS_AF2	2
#define GPIO_AS_AF3	3

#define ENABLE_EDGE	0
#define DISABLE_EDGE	1

#define GPIO_EDGE	1
#define GPIO_NOEDGE	0

int xs_getgpio_inLEV(int gpio_num)
{
	volatile int *regT;

	if(gpio_num < 32)
	{
		regT = (volatile int *)&GPLR0;
		if(*regT & (1 << (gpio_num % 32)))
			return GPIO_HIGH;
		else
			return GPIO_LOW;
	}
	if(gpio_num < 64)
	{
		regT = (volatile int *)&GPLR1;
		if(*regT & (1 << (gpio_num % 32)))
			return GPIO_HIGH;
		else
			return GPIO_LOW;
	}
	if(gpio_num < 96)
	{
		regT = (volatile int *)&GPLR2;
		if(*regT & (1 << (gpio_num % 32)))
			return GPIO_HIGH;
		else
			return GPIO_LOW;
	}
	if(gpio_num <= 120)
	{
		regT = (volatile int *)&GPLR3;
		if(*regT & (1 << (gpio_num % 32)))
			return GPIO_HIGH;
		else
			return GPIO_LOW;
	}
	return 0;
}

int module_on2pc_gpio_init()
{
    // ftuart_gpio_init
    xs_setgpio_AFR(34, GPIO_AS_AF1);
    xs_setgpio_dir(34, GPIO_PIN_IN);

    xs_setgpio_AFR(37, GPIO_AS_AF3);
    xs_setgpio_dir(37, GPIO_PIN_IN);

    xs_setgpio_AFR(26, GPIO_AS_AF3);
    xs_setgpio_dir(26, GPIO_PIN_IN);

    xs_setgpio_AFR(27, GPIO_AS_AF3);
    xs_setgpio_dir(27, GPIO_PIN_IN);

    xs_setgpio_AFR(39, GPIO_AS_GPIO);
    xs_setgpio_dir(39, GPIO_PIN_OUT);

    // bcm2121_gpio_init()
    //B_MODEM_WAKEUP
    xs_setgpio_AFR(114, GPIO_AS_GPIO);
    xs_setgpio_dir(114, GPIO_PIN_OUT);
    xs_setgpio_outhigh(114);

    //B_BB_HOST_WAKEUP
    xs_setgpio_AFR(38, GPIO_AS_GPIO);
    xs_setgpio_dir(38, GPIO_PIN_IN);

    //BT_32
    xs_setgpio_AFR(10, GPIO_AS_AF1);
    xs_setgpio_dir(10, GPIO_PIN_OUT);

    //BT_EJACK_RECO
    xs_setgpio_AFR(91, GPIO_AS_GPIO);
    xs_setgpio_dir(91, GPIO_PIN_IN);

    //B_BB_FLASH
    xs_setgpio_AFR(22, GPIO_AS_GPIO);
    xs_setgpio_dir(22, GPIO_PIN_OUT);

    //B_BB_RESETN
    xs_setgpio_AFR(23, GPIO_AS_GPIO);
    xs_setgpio_dir(23, GPIO_PIN_OUT);

    //B_ONKEY_N
    xs_setgpio_AFR(25, GPIO_AS_GPIO);
    xs_setgpio_dir(25, GPIO_PIN_OUT);

    return 0;
}

int module_gpio_init()
{
    // ftuart_gpio_init
    xs_setgpio_AFR(34, GPIO_AS_AF1);
    xs_setgpio_dir(34, GPIO_PIN_IN);

    xs_setgpio_AFR(37, GPIO_AS_AF3);
    xs_setgpio_dir(37, GPIO_PIN_OUT);

    xs_setgpio_AFR(26, GPIO_AS_AF3);
    xs_setgpio_dir(26, GPIO_PIN_IN);

    xs_setgpio_AFR(27, GPIO_AS_AF3);
    xs_setgpio_dir(27, GPIO_PIN_OUT);

    xs_setgpio_AFR(39, GPIO_AS_GPIO);
    xs_setgpio_dir(39, GPIO_PIN_OUT);

    // bcm2121_gpio_init()
    //B_MODEM_WAKEUP
    xs_setgpio_AFR(114, GPIO_AS_GPIO);
    xs_setgpio_dir(114, GPIO_PIN_OUT);
    xs_setgpio_outhigh(114);

    //B_BB_HOST_WAKEUP
    xs_setgpio_AFR(38, GPIO_AS_GPIO);
    xs_setgpio_dir(38, GPIO_PIN_IN);

    //BT_32
    xs_setgpio_AFR(10, GPIO_AS_AF1);
    xs_setgpio_dir(10, GPIO_PIN_OUT);

    //BT_EJACK_RECO
    xs_setgpio_AFR(91, GPIO_AS_GPIO);
    xs_setgpio_dir(91, GPIO_PIN_IN);

    //B_BB_FLASH
    xs_setgpio_AFR(22, GPIO_AS_GPIO);
    xs_setgpio_dir(22, GPIO_PIN_OUT);

    //B_BB_RESETN
    xs_setgpio_AFR(23, GPIO_AS_GPIO);
    xs_setgpio_dir(23, GPIO_PIN_OUT);

    //B_ONKEY_N
    xs_setgpio_AFR(25, GPIO_AS_GPIO);
    xs_setgpio_dir(25, GPIO_PIN_OUT);

    return 0;
}

int module_power_on()
{
    //OSCC TOUT_EN for 32K HZ_CLK bit2
    OSCC |= (0x1<<2);

    //set UART TX/RX/CTS/RTS/DTR direction

    GAFR1_L |= (0x1<<4);        // AF34 -> 0b?1
    GAFR1_L &= ~(0x1<<5);       // AF34 -> 0b01
    GPDR1 &= ~(0x1<<2);         // PD34 in

    GAFR1_L |= (0x3<<10);       // AF37 -> 0b11
    GPDR1 |= (0x1<<5);          // PD37 out

    GAFR0_U |= (0x3<<20);       // AF26 -> 0b11
    GPDR0 &= ~(0x1<<26);        // PD26 in

    GAFR0_U |= (0x3<<22);       // AF27 -> 0b11
    GPDR0 |= (0x1<<27);         // PD27 out

    GAFR1_L &= ~(0x3<<14);      // AF39 -> 0b00
    GPDR1 |= (0x1<<7);          // PD39 out

    GAFR0_U &= ~(0x3<<12);      // AF22 -> 0b00
    GPDR0 |= (0x1<<22);         // PD22 out
    GPCR0 |= 0x1<<22;           // PC22 -> clear pin level low

    //set BB_ONKEYN(GPIO25) high
    GPDR0 |= (0x1<<25);          // PD25 -> out
    GAFR0_U &= 0xFFF3FFFF;       // AF25 -> 0b00
    GPSR0 |= (0x1<<25);          // PS25 -> set pin level high


    //set BB_RESETN(GPIO23) low
    GPDR0 |= (0x1<<23);         // PD23 -> out
    GAFR0_U &= 0xFFFF3FFF;      // AF23 -> 0b00
    GPCR0 |= (0x1<<23);         // PC23 -> clear pin level low

    //keep BB_RESETN(GPIO23) low more than 100ms
    DzDelay(200000);

    //set BB_RESETN(GPIO23) high
    GPSR0 |= (0x1<<23);         // PS23 -> set pin level high

    //Wake up BCM2121 for the first time
    GPCR3 = (0x1 << 18);        // PC114 -> clear pin level low
    DzDelay(10000);
    GPSR3 = (0x1 << 18);        // PS114 -> set pin level high

    return 0;
}

int module_power_off()
{
    xs_setgpio_outlow(25);
    return 0;
}

int module_is_sleeping()
{
    //B_BB_HOST_WAKEUP
    if (xs_getgpio_inLEV(38) == GPIO_LOW) {
        return 1;
    }

    return 0;
}

int module_wake_up()
{
    xs_setgpio_outlow(114);
    DzDelay(1000 * 5);
    xs_setgpio_outhigh(114);
    return 0;
}

int module_sleep()
{
    xs_setgpio_outhigh(114);
    DzDelay(1000 * 5);
    xs_setgpio_outlow(114);
    DzDelay(40*1000);
    return 0;
}

int bluetooth_power_on()
{
    //B_BT_PWREN(GPIO82) set output
    GPDR2 |= 0x01 << 18;
    GAFR2_U &= ~(0x03 << 4);

    //B_BT_WAKE(GPIO19) set output
    GPDR0 |= 0x01 << 19;
    GAFR0_U &= ~(0x03 << 6);

    //B_BT_HOSTWAKE(GPIO90) set input
    GPDR2 &= ~(0x01 << 26);
    GAFR2_U &= ~(0x03 << 20);

    //B_BT_RESET(GPIO115) set output
    GPDR3 |= 0x01 << 19;
    GAFR3_U &= ~(0x03 << 6);

    //set B_BT_RXD(GPIO43)
    GPDR1 |= 0x01 << 11;
    GAFR1_L |= 0x02 << 22;

    //Start 13M clock
    GPDR2 |= 0x1 << 14;
    GAFR2_L &= ~(0x03 << 28);
    GPSR2 |= 0x1 << 14;

    //Start 32K clock
    GPDR0 |= 0x1 << 10;
    GAFR0_L &= ~(0x03 << 20);
    OSCC |= (0x1 << 2);

    //set B_BT_PWREN(GPIO82) high
    GPSR2 |= 0x1 << 18;

    //set B_BT_WAKE(GPIO19) high
    GPSR0 |= 0x1<<19;

    //set B_BT_RESET(GPIO115) high
    GPSR3 |= 0x1<<19;

    //set B_BT_RESET(GPIO115) low

    GPCR3 |= 0x1<<19;
    DzDelay(100 * 1000);

    //set B_BT_RESET(GPIO115) high
    GPSR3 |= 0x1<<19;

    return 0;
}

int bluetooth_power_off()
{
#if 0
    GPCR2 	|= 	0x1 << 18;
    DzDelay(100*1000);
#endif
    return 0;
}

static IDeviceDriver* g_pBTUartDriver;

int bluetooth_wake_up()
{
    if(GPLR2 & (0x1 << 18)) {
        //init bluetooth uart.
        if(NULL==g_pBTUartDriver)
            DzFindService(L"device:serial2",(IInterface **)&g_pBTUartDriver);
        SERIAL_INFO info;
        info.baud = NUM_SERIAL_BAUD_115200;
        info.stop = NUM_SERIAL_STOP_1;
        info.parity = NUM_SERIAL_PARITY_NONE;
        info.word_length = NUM_SERIAL_WORD_LENGTH_8;
        info.flags =
            NUM_SERIAL_FLOW_DSRDTR_RX |
            NUM_SERIAL_FLOW_RTSCTS_TX |
            NUM_SERIAL_FLOW_RTSCTS_RX |
            NUM_SERIAL_FLOW_DSRDTR_TX;

        MemoryBuf ebcfgData((Byte *)&info, sizeof(info));
        g_pBTUartDriver->Control(0x00020000 | 0x0174, ebcfgData, NULL, NULL);

        BTLCR &= ~(0x01 <<6);
        Gpio_SetAFR(45,0);
    	GPCR1 |= (0x1<<13);
        DzDelay(5*1000);
        Gpio_SetAFR(45,2);
    	cprintf("BT is wakeup \n");
    }

	return 0;
}

int bluetooth_sleep()
{
    if(GPLR2 & (0x1 << 18)) {

        BTLCR |= 0x01 <<6;

    	Gpio_SetAFR(45,0);
    	Gpio_SetDir(45,GPIO_PIN_OUT);
    	GPSR1 |= (0x1<<13);

    	DzDelay(5*1000);
    	cprintf("BT is sleep \n");
    }

    return 0;
}

